package si.yun.utils;


import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;

import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.domain.proto.storage.DownloadByteArray;
import com.github.tobato.fastdfs.service.FastFileStorageClient;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;

import java.util.*;

import net.coobird.thumbnailator.Thumbnails;
import java.io.ByteArrayOutputStream;


/**
 * @program: equipment2
 * @description:
 * @author: 崔晓晨
 * @create: 2021-09-28 16:26
 **/
@Component
public class TestAliUpload {
    public static final String DEFAULT_CHARSET = "UTF-8";
    @Value("${endpoint}")
    String endpoint;
    @Value("${keyId}")
    String keyId;
    @Value("${keySecret}")
    String keySecret;
    @Value("${bucketName}")
    String bucketName;
    @Autowired
    private FastFileStorageClient fastFileStorageClient;

    /**
     * 上传
     * @param file
     * @return
     * @throws IOException
     */
    public String upload(MultipartFile file){
        try {

            // 创建OSS实例。
            OSS ossClient = new OSSClientBuilder().build(endpoint, keyId, keySecret);

            //获取上传文件输入流
            InputStream inputStream = file.getInputStream();
            //获取文件名称
            String fileName = file.getOriginalFilename();

            int i = fileName.lastIndexOf('.');
            String fileType = fileName.substring(i+1);
            if(      fileType.equals("JPG")||fileType.equals("jpg")||
                    fileType.equals("png")||fileType.equals("gif")||
                    fileType.equals("tif")||fileType.equals("bmp")||
                    fileType.equals("jpeg"))
            {
                String upload = createUpload(file, ossClient, bucketName);
                return upload;
            }


            //1 在文件名称里面添加随机唯一的值
            String uuid = UUID.randomUUID().toString().replaceAll("-","");
            // yuy76t5rew01.jpg
            fileName = uuid+fileName;

            //2 把文件按照日期进行分类
            //获取当前日期
            //   2019/11/12
            Calendar now = Calendar.getInstance();
            String datePath =now.get(Calendar.YEAR)+"-"+(now.get(Calendar.MONTH) + 1)+"";
            //拼接
            //  2019/11/12/ewtqr313401.jpg
            fileName = "siyun/data/"+datePath+"/"+fileName;

            //调用oss方法实现上传
            //第一个参数  Bucket名称
            //第二个参数  上传到oss文件路径和文件名称   aa/bb/1.jpg
            //第三个参数  上传文件输入流
            PutObjectResult putObjectResult = ossClient.putObject(bucketName, fileName, inputStream);
            System.out.println(putObjectResult);

            // 关闭OSSClient。
            ossClient.shutdown();

            //把上传之后文件路径返回
            //需要把上传到阿里云oss路径手动拼接出来
            //  https://edu-guli-1010.oss-cn-beijing.aliyuncs.com/01.jpg
            String url = "/"+fileName;
            System.out.println(url);
            return url;
        }catch(Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 删除
     * @param path
     */
    public void delete(String path) {
        fastFileStorageClient.deleteFile(path);
    }

    /**
     * 删除
     * @param group
     * @param path
     */
    public void delete(String group,String path) {
        fastFileStorageClient.deleteFile(group,path);
    }

    /**
     * 文件下载
     * @param path 文件路径，例如：/group1/path=M00/00/00/itstyle.png
     * @param filename 下载的文件命名
     * @return
     */
    public void download(String path, String filename, HttpServletResponse response) throws IOException {

        // 获取文件
        StorePath storePath = StorePath.parseFromUrl(path);
        if (StringUtils.isBlank(filename)) {
            filename = FilenameUtils.getName(storePath.getPath());
        }
        byte[] bytes = fastFileStorageClient.downloadFile(storePath.getGroup(), storePath.getPath(), new DownloadByteArray());
        response.reset();
        response.setContentType("applicatoin/octet-stream");
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
        ServletOutputStream out = response.getOutputStream();
        out.write(bytes);
        out.close();
    }
    public static String  createUpload(@RequestParam("file") MultipartFile file,OSS ossClient,String bucketName) throws Exception {
        System.out.println("图片");
        ObjectMetadata objectMetadata = new ObjectMetadata();
        String fileName = file.getOriginalFilename();
        //1 在文件名称里面添加随机唯一的值
        String uuid = UUID.randomUUID().toString().replaceAll("-","");
        // yuy76t5rew01.jpg
        fileName = uuid+fileName;
        //2 把文件按照日期进行分类
        //获取当前日期
        //   2019/11/12
        Calendar now = Calendar.getInstance();
        String datePath =now.get(Calendar.YEAR)+"-"+(now.get(Calendar.MONTH) + 1)+"";
        //拼接
        //  2019/11/12/ewtqr313401.jpg

        fileName = "siyun/data/"+datePath+"/"+fileName;
        byte[] bytes = file.getBytes();
        //调用图片压缩方法，这里压缩到500k左右
        bytes = compressPicForScale(bytes,500);
        InputStream sbs = new ByteArrayInputStream(bytes);
        objectMetadata.setContentLength(bytes.length);
        objectMetadata.setContentType(file.getContentType());
        //获取文件后缀名
        String ext = FilenameUtils.getExtension(file.getOriginalFilename());
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, fileName, sbs, objectMetadata);

        PutObjectResult re = ossClient.putObject(putObjectRequest);
        // 关闭OSSClient。
        ossClient.shutdown();

        String url = "/"+fileName;
        System.out.println(url);
        return url;
    }

    /*
     *	以下是常量,按照阿里代码开发规范,不允许代码中出现魔法值
     */
    private static final Integer ZERO = 0;
    private static final Integer ONE_ZERO_TWO_FOUR = 1024;
    private static final Integer NINE_ZERO_ZERO = 900;
    private static final Integer THREE_TWO_SEVEN_FIVE = 3275;
    private static final Integer TWO_ZERO_FOUR_SEVEN = 2047;
    private static final Double ZERO_EIGHT_FIVE = 0.85;
    private static final Double ZERO_SIX = 0.6;
    private static final Double ZERO_FOUR_FOUR = 0.44;
    private static final Double ZERO_FOUR = 0.4;

    /**
     * 根据指定大小压缩图片
     *
     * @param imageBytes  源图片字节数组
     * @param desFileSize 指定图片大小，单位kb
     * @return 压缩质量后的图片字节数组
     */
    public static byte[] compressPicForScale(byte[] imageBytes, long desFileSize) {
        if (imageBytes == null || imageBytes.length <= ZERO || imageBytes.length < desFileSize * ONE_ZERO_TWO_FOUR) {
            return imageBytes;
        }
        long srcSize = imageBytes.length;
        double accuracy = getAccuracy(srcSize / ONE_ZERO_TWO_FOUR);
        try {
            while (imageBytes.length > desFileSize * ONE_ZERO_TWO_FOUR) {
                ByteArrayInputStream inputStream = new ByteArrayInputStream(imageBytes);
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream(imageBytes.length);
                Thumbnails.of(inputStream)
                        .scale(accuracy)
                        .outputQuality(accuracy)
                        .toOutputStream(outputStream);
                imageBytes = outputStream.toByteArray();
            }
        } catch (Exception e) {
            e.printStackTrace();
            return  null;
        }
        return imageBytes;
    }

    /**
     * 自动调节精度(经验数值)
     *
     * @param size 源图片大小
     * @return 图片压缩质量比
     */
    private static double getAccuracy(long size) {
        double accuracy;
        if (size < NINE_ZERO_ZERO) {
            accuracy = ZERO_EIGHT_FIVE;
        } else if (size < TWO_ZERO_FOUR_SEVEN) {
            accuracy = ZERO_SIX;
        } else if (size < THREE_TWO_SEVEN_FIVE) {
            accuracy = ZERO_FOUR_FOUR;
        } else {
            accuracy = ZERO_FOUR;
        }
        return accuracy;
    }
}
